package com.mc.fastkit.ext

import android.text.Spannable
import android.text.style.AbsoluteSizeSpan
import android.text.style.StyleSpan
import android.util.Base64
import android.util.Patterns
import androidx.core.text.toSpannable
import com.mc.fastkit.utils.EncodeUtils
import java.util.Locale

fun String.toBase64(flags: Int = Base64.NO_WRAP): ByteArray {
    return EncodeUtils.encode2Base64(this.toByteArray(), flags)
}

fun String.toBase64String(flags: Int = Base64.NO_WRAP): String {
    return EncodeUtils.encode2Base64String(this.toByteArray(), flags)
}

fun String.toHexByteArray(): ByteArray {
    require(length % 2 == 0) { "长度不是偶数" }
    val hexBytes = uppercase(Locale.getDefault()).toCharArray()
    val ret = ByteArray(length ushr 1)
    var i = 0
    while (i < length) {
        ret[i shr 1] = (hexBytes[i].hex2Dec() shl 4 or hexBytes[i + 1].hex2Dec()).toByte()
        i += 2
    }
    return ret
}

fun String.hexString2Bytes(): ByteArray {
    var hexString = this
    var len = hexString.length
    if (len % 2 != 0) {
        hexString = "0$hexString"
        len += 1
    }
    val hexBytes = hexString.uppercase(Locale.getDefault()).toCharArray()
    val result = ByteArray(len shr 1)
    var i = 0
    while (i < len) {
        result[i shr 1] = (hexBytes[i].hex2Dec() shl 4 or hexBytes[i + 1].hex2Dec()).toByte()
        i += 2
    }
    return result
}

private fun Char.hex2Dec(): Int {
    return when (this) {
        in '0'..'9' -> {
            this - '0'
        }

        in 'A'..'F' -> {
            this - 'A' + 10
        }

        else -> {
            throw IllegalArgumentException()
        }
    }
}

/**
 * 判断是否是手机号码
 * 中国移动: 134(0-8), 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 165, 172, 178,
 * 182, 183, 184, 187, 188, 195, 197, 198
 * 中国联通: 130, 131, 132, 145, 155, 156, 166, 167, 175, 176, 185, 186, 196
 * 中国电信: 133, 149, 153, 162, 173, 177, 180, 181, 189, 190, 191, 199
 * 中国广电: 192
 * 移动卫星: 1349
 * 虚拟号: 170, 171
 * @receiver String
 * @return Boolean
 */
fun String.isMobileNum(): Boolean {
    return "^((13[0-9])|(14[579])|(15[0-35-9])|(16[2567])|(17[0-35-8])|(18[0-9])|(19[0-35-9]))\\d{8}\$".toRegex()
        .matches(this)
}

/**
 * 是否是电话号码
 * @receiver String
 * @return Boolean
 */
fun String.isPhoneNum(): Boolean {
    return Patterns.PHONE.toRegex().matches(this)
}

/**
 * 是否是身份证号码
 * @receiver String
 * @return Boolean
 */
fun String.isIdCardNum(): Boolean {
    return "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}\$".toRegex().matches(this)
}

/**
 * 判断是否是邮箱
 * @receiver String
 * @return Boolean
 */
fun String.isEmail(): Boolean {
    return Patterns.EMAIL_ADDRESS.toRegex().matches(this)
}

/**
 * 判断是否是域名
 * @receiver String
 * @return Boolean
 */
fun String.isDomain(): Boolean {
    return Patterns.DOMAIN_NAME.toRegex().matches(this)
}

/**
 * 判断是否是URL地址
 * @receiver String
 * @return Boolean
 */
fun String.isInternetUrl(): Boolean {
    return "[a-zA-z]+://\\S*".toRegex().matches(this)
}

/**
 * 是否是个汉字
 * @receiver String
 * @return Boolean
 */
fun String.isZh(): Boolean {
    return "^[\\u4e00-\\u9fa5]+$".toRegex().matches(this)
}

/**
 * 是否是IP地址
 * @receiver String
 * @return Boolean
 */
fun String.isIpAddress(): Boolean {
    return Patterns.IP_ADDRESS.toRegex().matches(this)
}

/**
 * 格式化数字（包括数字和小数点，但排除汉字和英文字母）
 * @receiver CharSequence
 * @param textSize 字体大小
 * @param typeface [StyleSpan]
 * @return CharSequence
 */
fun CharSequence.formatNumber(textSize: Int, typeface: Int? = null): CharSequence {
    return this.formatNumber { spannable, start, end ->
        spannable.setSpan(
            AbsoluteSizeSpan(dp2pxi(textSize)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )
        if (typeface != null) {
            spannable.setSpan(StyleSpan(typeface), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    }
}

/**
 * 格式化数字（包括数字和小数点，但排除汉字和英文字母）
 * @receiver CharSequence
 * @param predicate Spannable处理
 * @return CharSequence
 */
fun CharSequence.formatNumber(predicate: (spannable: Spannable, start: Int, end: Int) -> Unit): CharSequence {
    val spStr = toSpannable()
    val matches = Regex("\\d+(\\.\\d+)?|\\.\\d+").findAll(this)
    matches.forEach { matchResult ->
        val start = matchResult.range.first
        val end = matchResult.range.last + 1
        predicate.invoke(spStr, start, end)
    }
    return spStr
}

/**
 * 格式化文本（包括汉字和英文字母，但排除数字和符号）
 * @receiver CharSequence
 * @param textSize 字体大小
 * @param style [StyleSpan]
 * @return CharSequence
 */
fun CharSequence.formatText(textSize: Int, style: Int? = null): CharSequence {
    return this.formatText { spannable, start, end ->
        spannable.setSpan(
            AbsoluteSizeSpan(dp2pxi(textSize)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )
        if (style != null) {
            spannable.setSpan(StyleSpan(style), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    }
}

/**
 * 格式化文本（包括汉字和英文字母，但排除数字和符号）
 * @receiver CharSequence
 * @param predicate Spannable处理
 * @return CharSequence
 */
fun CharSequence.formatText(predicate: (spannable: Spannable, start: Int, end: Int) -> Unit): CharSequence {
    val spStr = toSpannable()
    val matches = Regex("[a-zA-Z\\u4e00-\\u9fa5]+").findAll(this)
    matches.forEach { matchResult ->
        val start = matchResult.range.first
        val end = matchResult.range.last + 1
        predicate.invoke(spStr, start, end)
    }
    return spStr
}

inline fun CharSequence?.ifNullOrEmpty(defaultValue: () -> CharSequence): CharSequence {
    return if (isNullOrEmpty()) defaultValue() else this.cast()
}
